﻿using iTool_Cetector.Result;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;

namespace iTool_Cetector.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class LinuxController : Controller
    {
        [HttpPost]
        public LinuxSystemStatus GetStatus()
        {

#if DEBUG
            return new LinuxSystemStatus
            {
                CPU = "5%",
                MEMUSAGE = 10,
                MEMTOTAL = 10,
                MEMUSAGEString = "10GiB",
                MEMTOTALString = "10GiB",
                MEM = "30%",
                BLOCKIOTOTAL = "10GiB",
                BLOCKIOUSAGE = "10GiB",
                BLOCKIO = "20%",
            };
#endif
            bool isKibUnit = true;

            var printTop = Utils.Excuter($"top -b -n 1");
            // printTop = System.IO.File.ReadAllText("linuxsystem.txt");

            printTop = this.CommonReplace(printTop);

            var lines = printTop.Split("\n");

            List<string> useLines = lines.Where(item => item.StartsWith("%Cpu(s)") || item.StartsWith("KiB Mem") || item.StartsWith("MiB Mem")).ToList();
            isKibUnit = useLines.Any(item => item.Contains("KiB Mem"));

            var cpuInfoParameters = useLines[0].Replace(" ", "").TrimStart("%Cpu(s):".ToCharArray()).TrimEnd('\r').Split(',').Where(item => !string.IsNullOrWhiteSpace(item)).ToList();

            var memInfoParameters = useLines[1].Replace(" ", "").TrimStart("KiBMem:".ToCharArray()).TrimEnd('\r').Split(',').Where(item => !string.IsNullOrWhiteSpace(item)).ToList();

            // us — 用户空间占用CPU的百分比。
            // sy — 内核空间占用CPU的百分比。
            // ni — 改变过优先级的进程占用CPU的百分比
            // id — 空闲CPU百分比
            // https://www.cnblogs.com/edgedance/p/7044753.html

            string
                us = cpuInfoParameters.Where(item => item.EndsWith("us")).FirstOrDefault().Replace("%", "").Replace("us", ""),
                sy = cpuInfoParameters.Where(item => item.EndsWith("sy")).FirstOrDefault().Replace("%", "").Replace("sy", ""),
                id = cpuInfoParameters.Where(item => item.EndsWith("id")).FirstOrDefault().Replace("%", "").Replace("id", "");

            // 8306544k total — 物理内存总量（8GB）
            // 7775876k used — 使用中的内存总量（7.7GB）
            // 530668k free — 空闲内存总量（530M）

            string
                total = memInfoParameters.Where(item => item.EndsWith("total")).FirstOrDefault().Replace("k", "").Replace("total", ""),
                used = memInfoParameters.Where(item => item.EndsWith("used")).FirstOrDefault().Replace("k", "").Replace("used", ""),
                free = memInfoParameters.Where(item => item.EndsWith("free")).FirstOrDefault().Replace("k", "").Replace("free", "");


            double.TryParse(us, out double usInt);
            double.TryParse(sy, out double syInt);
            double.TryParse(id, out double idInt);

            double.TryParse(total, out double totalInt);
            double.TryParse(used, out double usedInt);
            double.TryParse(free, out double freeInt);

            // 磁盘信息
            var printDF = Utils.Excuter($"df -h");
            // printDF = System.IO.File.ReadAllText("df.txt");

            lines = printDF.Split("\n").Select(item => item.Trim()).ToArray();

            useLines = lines.Where(item => item.StartsWith("/dev")).ToList();
            var dflist = new List<string>();

            var infos = useLines.Select(item => item.Replace("G","").Split(' ').Where(itemString => !string.IsNullOrWhiteSpace(itemString)).ToList()).ToList();

            double dskTotal = 0,dskUsage = 0;
            foreach (var item in infos)
            {
                double.TryParse(item[1],out double itemDskTotal);
                double.TryParse(item[2],out double itemDskUsage);
                dskTotal += itemDskTotal;
                dskUsage += itemDskUsage;
            }


            return new LinuxSystemStatus
            {
                CPU = usInt + syInt + "%",
                MEMUSAGE = isKibUnit ? usedInt : usedInt * 1024,
                MEMTOTAL = isKibUnit ? totalInt : totalInt * 1024,
                MEMUSAGEString = Math.Round((double)(isKibUnit ? (usedInt / 1024 / 1024) : (usedInt / 1024)), 2) + "GiB",
                MEMTOTALString = Math.Round((double)(isKibUnit ? (totalInt / 1024 / 1024) : (totalInt / 1024)), 2) + "GiB",
                MEM = Math.Round((double)(usedInt / totalInt * 100), 2) + "%",
                BLOCKIOTOTAL = dskTotal + "GiB",
                BLOCKIOUSAGE = dskUsage + "GiB",
                BLOCKIO = Math.Round((double)(dskUsage / dskTotal * 100), 2) + "%",
            };
        }


        [HttpPost("{processName}")]
        public LinuxProcessStatus GetDotnetStatus(string processName)
        {
            try
            {
                var printDotnet = Utils.Excuter($"pgrep -a dotnet");
                 //printDotnet = System.IO.File.ReadAllText("pgrep-adotnet.txt");

                printDotnet = this.CommonReplace(printDotnet);

                var lines = printDotnet.Split("\n");
                var useLine = lines.Where(item => item.Contains(processName)).FirstOrDefault();

                if (!string.IsNullOrWhiteSpace(useLine))
                {
                    var parameters = useLine.Split(' ');
                    int.TryParse(parameters[0], out int pid);

                    if (pid > 0)
                    {
                        string print = Utils.Excuter($"top -p {pid} -b -n 1");
                        // print = System.IO.File.ReadAllText("toppid.txt");
                        print = this.CommonReplace(print);

                        lines = print.Split("\n").Select(item => item.Trim()).ToArray();
                        useLine = lines.Where(item => item.StartsWith(parameters[0])).FirstOrDefault();

                        //PID — 进程id
                        //USER — 进程所有者
                        //PR — 进程优先级
                        //NI — nice值。负值表示高优先级，正值表示低优先级
                        //VIRT — 进程使用的虚拟内存总量，单位kb。VIRT=SWAP+RES
                        //RES — 进程使用的、未被换出的物理内存大小，单位kb。RES=CODE+DATA
                        //SHR — 共享内存大小，单位kb
                        //S — 进程状态。D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程
                        //%CPU — 上次更新到现在的CPU时间占用百分比
                        //%MEM — 进程使用的物理内存百分比
                        //TIME+ — 进程使用的CPU时间总计，单位1/100秒
                        //COMMAND — 进程名称（命令名/命令行）

                        parameters = useLine.Split(' ').Where(item => !string.IsNullOrWhiteSpace(item)).ToArray();

                        return new LinuxProcessStatus
                        {
                            CPU = double.Parse(parameters[8]) / 100,
                            CPUString = parameters[8] + "%",
                            MEM = double.Parse(parameters[9]) / 100,
                            MEMString = parameters[9] + "%",
                            TIME = parameters[10]
                        };

                    }
                    else
                    {
                        return new LinuxProcessStatus
                        {
                            CPU = -1
                        };
                    }

                }
            }
            catch (Exception ex)
            {

                Utils.Logger($"GetDotnetStatus:{processName},  {Newtonsoft.Json.JsonConvert.SerializeObject(ex)}");

                return new LinuxProcessStatus
                {
                    CPU = -1
                };
            }

            return default;
        }


        string CommonReplace(string input) 
        {
            input = input.TrimStart('\r').TrimStart('\n');
            input = input.TrimEnd('\r').TrimEnd('\n');
            return input;
        }

    }
}
